package com.dong.repeatsubmit.redis;

import com.dong.repeatsubmit.util.SpringContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.RedissonLock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @Description: 分布式锁
 * @Author huanlin.geng
 * @Date 2022/5/28
 **/
@Slf4j
public class RedissonLockUtil {

    /**
     * 分布式锁前缀
     */
    private static final String KEY = "RedissonLock:";

    private static final AppRedisService REDIS_BASE_UTIL = SpringContextUtil.getBean(AppRedisService.class);

    private static RedissonClient REDISSON = SpringContextUtil.getBean(RedissonClient.class);


    /**
     * 使用分布式锁。 不传失效时间。默认底层是30s失效。并且看门狗10秒检查一次，做一次续命。
     *
     * @param lockName key
     * @param fairLock 是否使用公平锁
     * @return
     */
    public static RedissonLock lock(String lockName, boolean fairLock) {
        RedissonLock lock = getLock(getKey(lockName), fairLock);
        lock.lock();
        return lock;
    }

    public static boolean tryLock(String lockName, boolean fairLock) {
        return privateTryLock(lockName, fairLock);
    }

    private static String getKey(String lockName) {
        return REDIS_BASE_UTIL.getKey(KEY + lockName);
    }

    /**
     * 使用分布式锁。 不传失效时间。默认底层是30s失效。并且看门狗10秒检查一次，做一次续命。
     * 尝试分布式锁，使用锁默认等待时间、超时时间。 waitTime为0表示尝试加锁不成功。立即返回失败。
     * 如果加锁失败需要阻塞则使用lock。
     *
     * @param lockName key
     * @param fairLock 是否使用公平锁
     * @return 加锁是否成功
     */
    private static boolean privateTryLock(String lockName, boolean fairLock) {
        RedissonLock lock = getLock(getKey(lockName), fairLock);
        try {
            return lock.tryLock(0, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            log.info("获取锁失败", e);
            Thread.currentThread().interrupt();
            return false;
        }
    }

    /**
     * 释放锁
     *
     * @param lockName
     */
    public static void unlock(String lockName, boolean fairLock) {
        RedissonLock lock = getLock(getKey(lockName), fairLock);
        if (lock != null && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }

    /**
     * 释放锁
     *
     * @param lock
     */
    private static void unlock(RLock lock) {
        if (lock != null && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }


    /**
     * true 获取公平锁 false 获取非公平锁
     *
     * @param lockName
     * @param fairLock
     * @return
     */

    private static RedissonLock getLock(String lockName, boolean fairLock) {
        RedissonLock lock;
        if (fairLock) {
            lock = (RedissonLock) REDISSON.getFairLock(lockName);
        } else {
            lock = (RedissonLock) REDISSON.getLock(lockName);
        }
        return lock;
    }
}